#!/usr/bin/python
# -*- coding: utf-8 -*-
import argparse
import readline
import logging

import emsyco.modules

_INDENTATION = '    ' #The pattern for indenting contexts

#Create a console-friendly logger, with the default level set to
#warn, so that the library modules can also use the logging facilities
#for CLI and daemon modes
_logger = logging.getLogger('cli')
_logger.setLevel(logging.DEBUG)
logging.basicConfig()

class IOSProcessor(object):
    _possibilities = None #A sequence of matching completions for the current operation, transient and short-lived
    _namespace = None #A collection of namespace elements usable in the current context
    _context_commit = None #A callback to invoke when the context is to be committed
    
    _kwargs = None
    
    def __init__(self, namespace, kwargs, context_commit=None, depth=0):
        """
        namespace comes from the loaded libraries,
        a collection of functions that can be used to evaluate the
        completeness of a line.
        
        kwargs are argument values passed through context shifts.
        """
        self._namespace = namespace
        self._kwargs = kwargs
        self._context_commit = context_commit
        self._depth = depth
        
    def _process(self, text):
        tokens = text.split()
        if not tokens:
            return
            
        for element in self._namespace:
            identification = element.identifier(tokens)
            if identification.complete:
                try:
                    result = element.handler(identification.tokens, self._kwargs or {})
                except Exception as e:
                    _logger.error(str(e))
                else:
                    if result:
                        if result.message:
                            print(result.message)
                        if result.context:
                            IOSProcessor(result.context.namespace, result.context.kwargs, context_commit=result.context.commit_callback, depth=(self._depth + 1)).process()
                break
        else:
            _logger.error("Unsupported command")
            
    def _complete(self, text, state):
        if state == 0: #Always set to 0 when generating a new completion-set
            buffer = readline.get_line_buffer()
            tokens = buffer.split()
            end_of_token = buffer.endswith(' ')
            possibilities = set()
            possibilities_found = False
            for element in self._namespace:
                new_possibilities = element.identifier(tokens).possibilities
                if new_possibilities:
                    possibilities_found = True
                    if tokens and not end_of_token:
                        new_possibilities = [p for p in new_possibilities if p.startswith(tokens[-1])]
                    possibilities.update(new_possibilities)
            if not end_of_token and not possibilities and possibilities_found:
                self._possibilities = (tokens[-1],)
            else:
                self._possibilities = tuple(reversed(sorted(possibilities)))
                
        if len(self._possibilities) > state:
            return self._possibilities[state] + ' '
        return None
        
    def process(self):
        old_completer = readline.get_completer()
        readline.set_completer(self._complete)
        try:
            while True:
                try:
                    line = raw_input("{indentation}> ".format(
                        indentation=(_INDENTATION * self._depth),
                    ))
                except EOFError:
                    print('')
                    break
                except KeyboardInterrupt:
                    print('')
                    continue
                else:
                    if line == '!':
                        if self._context_commit:
                            try:
                                self._context_commit(self._kwargs)
                            except Exception as e:
                                _logger.error(str(e))
                                continue
                        break
                    self._process(line)
        finally:
            readline.set_completer(old_completer)

# Use the tab key for completion
readline.parse_and_bind('tab: complete')
# Use the ? key for completion, too
readline.parse_and_bind('?: complete')

IOSProcessor(emsyco.modules.NAMESPACE_IOS, None).process()
